package com.junqi.media.hls;

import com.junqi.common.entity.AjaxResult;
import lombok.extern.slf4j.Slf4j;
import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.ffmpeg.global.avutil;
import org.bytedeco.javacv.*;
import org.bytedeco.javacv.Frame;
import org.bytedeco.opencv.opencv_core.IplImage;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.concurrent.Future;

@Slf4j
public class HlsTask implements Runnable {

    /**
     * rtmp流url
     */
    private final String rtmpUrl;
    /**
     * hls文件存储路径
     */
    private final String filePath;
//
//    /**
//     * 直播流code
//     */
//    private final String rtmpCode;

    private final String roomId;

    private volatile boolean running = false;

    private static final int MAX_RETRIES = 10;  // 最大重试次数
    private static final int RETRY_DELAY_MS = 5000;  // 重试延迟（毫秒）

    private FFmpegFrameGrabber grabber;//拉流器
    private FFmpegFrameRecorder recorder;//录制器
    private boolean grabberStatus = false;
    private boolean recorderStatus = false;

    public HlsTask(String rtmpUrl, String filePath,String roomId) {
        this.rtmpUrl = rtmpUrl;
        this.filePath = filePath;
        this.roomId = roomId;
    }

    @Override
    public void run() {
        // 设置 FFmpeg 日志回调
        avutil.av_log_set_level(avutil.AV_LOG_ERROR); // 设置日志级别
        FFmpegLogCallback.set();

        String m3u8Url=filePath+roomId+ File.separator +"video.m3u8";
        // 创建一个File对象
        File file = new File(m3u8Url);
        // 获取文件的父目录
        File parentDir = file.getParentFile();
        // 如果父目录不存在，则创建它
        if (parentDir != null && !parentDir.exists()) {
            parentDir.mkdirs();
        }

        int retryCount = 0;
        while (retryCount < MAX_RETRIES) {
            try {
                grabberStatus = startGrabber();// 拉流器
                recorderStatus = startRecorder(m3u8Url,grabber);// 推流录制器
                break;  // 成功抓取后退出重试
            } catch (Exception e) {
                retryCount++;
                log.info("流未开始推送，正在重试... 第 " + retryCount + " 次重试");
                try {
                    Thread.sleep(RETRY_DELAY_MS);  // 等待一段时间后重试
                } catch (InterruptedException ex) {
                    ex.printStackTrace();
                }
            }
        }
        running=true;
        // 时间戳计算
        long startTime = 0;
        long videoTS = 0;
        long lastCaptureTime = 0;  // 上次截图的时间
        for (;running && grabberStatus && recorderStatus;) {
            try {
                // 转码
                long startGrab = System.currentTimeMillis();
                Frame frame = grabber.grab(); // 这边判断相机断网，正常50左右，断线15000
                if ((System.currentTimeMillis() - startGrab) > 5000) {
                    //						doReConnect();
                    //						continue;
                    log.info("\r\n{}\r\n视频流网络异常>>>", rtmpUrl);
                    break;
                }
                if (frame != null) {
                    if (startTime == 0) {
                        startTime = System.currentTimeMillis();
                    }
                    videoTS = 1000 * (System.currentTimeMillis() - startTime);
                    // 判断时间偏移
                    if (videoTS > recorder.getTimestamp()) {
                        // System.out.println("矫正时间戳: " + videoTS + " : " + recorder.getTimestamp() + "
                        // -> "
                        // + (videoTS - recorder.getTimestamp()));
                        recorder.setTimestamp((videoTS));
                    }
                    // 每3分钟获取一次封面截图
                    if ((System.currentTimeMillis() - lastCaptureTime) >= 180000 && !(frame.imageWidth <= 0 || frame.imageHeight <= 0)) { // 180000ms = 3分钟
                        lastCaptureTime = System.currentTimeMillis();
                        // 截取帧并保存为封面图
                        saveCoverImage(frame);
                    }
                    // 录制带有水印的帧
                    recorder.record(frame);
                }
            } catch (Exception e) {
                grabberStatus = false;
                recorderStatus = false;
                HlsHandler.taskMap.remove(roomId);
                log.info("推拉流发生异常-e，{} ", e);
            }
        }
        try {
            // 关闭录制器和抓取器
            recorder.close();
            grabber.close();
            log.info("关闭媒体流-javacv，{} ", rtmpUrl);
        } catch (Exception e) {
            log.info("任务完成或中断,streamCode: "+roomId+"，原因：" + e.getMessage());
            e.printStackTrace();
        }finally {
            running=false;
            HlsHandler.taskMap.remove(roomId);
        }
    }

    /**
     *  创建FfmpegFrameRecorder对象，用于录制M3U8格式的视频
     * @param m3u8Url
     * @return
     */
    private boolean startRecorder(String m3u8Url,FFmpegFrameGrabber grabber) {
        recorder = new FFmpegFrameRecorder(
                m3u8Url,// m3u8文件输出地址，也可设置为请求上传地址（需准备好请求api）
                grabber.getImageWidth(),
                grabber.getImageHeight(),
                grabber.getAudioChannels());
        recorder.setFormat("hls");// 设置输出格式为HLS（HTTP Live Streaming）
        recorder.setOption("hls_time", "3");// 设置每个HLS片段的时间长度为5秒
        recorder.setOption("hls_list_size", "1");// 设置播放列表中的片段数量，0表示不限制
        recorder.setOption("hls_flags", "delete_segments");// 设置删除旧片段的标志
        recorder.setOption("hls_wrap", "6");
        recorder.setOption("hls_delete_threshold", "1");// 设置删除片段的阈值
        recorder.setOption("hls_segment_type", "mpegts");// 设置HLS片段的类型为mpegts
        recorder.setOption("hls_base_url", "/media/hls/ts?roomId="+roomId+"&tsName=");// ts文件开头
        recorder.setOption("hls_segment_filename", filePath + roomId + File.separator+"%d.ts");// 设置HLS片段的文件名模板，%d会被替换为序列号 ts文件输出地址
//        recorder.setOption("hls_key_info_file", infoUrl);// 设置密钥信息文件的URL，酌情设置
        // 设置请求上传方式为POST
//        recorder.setOption("method", "POST");// 将输出片段通过请求上传时设置
        recorder.setGopSize((int) grabber.getFrameRate()); // 尝试将 GOP 设置为帧率的整数倍
        recorder.setFrameRate(grabber.getFrameRate()); // 确保帧率与源视频一致
        recorder.setVideoQuality(1.0);// 设置视频质量（1.0表示无损）
        recorder.setVideoBitrate(1920 * 1080);// 设置视频比特率，此设置可调清晰度
        recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);// 设置视频编码器为H264
        recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC); // 设置音频编码器
        recorder.setAudioChannels(grabber.getAudioChannels()); // 设置音频通道数
        recorder.setSampleRate(grabber.getSampleRate()); // 设置音频采样率
        recorder.setTrellis(1);
        recorder.setMaxDelay(0);// 设置延迟
        try {
            recorder.start();// 开始录制
            log.info("启动转码录制器成功");
        } catch (FFmpegFrameRecorder.Exception e) {
            log.info("启动转码录制器失败", e);
            e.printStackTrace();
            AjaxResult.errorRun("启动转码录制器失败："+e);
        }
        return true;
    }

    /**
     * 创建拉流器
     * @return
     */
    private boolean startGrabber() {
        grabber = new FFmpegFrameGrabber(rtmpUrl);
        try {
            // 超时时间(15秒)
            grabber.setOption("stimeout", "5000000");//网络超时 ffmpeg默认5秒，这里设置15秒
            grabber.setOption("threads", "1");
            // grabber.setPixelFormat(avutil.AV_PIX_FMT_YUV420P);
            // 设置缓存大小，提高画质、减少卡顿花屏
            grabber.setOption("buffer_size", "1024000");
            // 读写超时，适用于所有协议的通用读写超时
            grabber.setOption("rw_timeout", "5000000");//读写超时，默认5秒
            // 探测视频流信息，为空默认5000000微秒
            grabber.setOption("probesize", "5000000");//读写超时，默认5秒
            // 解析视频流信息，为空默认5000000微秒
            grabber.setOption("analyzeduration", "5000000");//读写超时，默认5秒
            // rtmp拉流缓冲区，默认3000毫秒
            grabber.setOption("rtmp_buffer", "1000");
            grabber.start();// 开始抓取
            log.info("\r\n{}\r\n启动拉流器成功", rtmpUrl);
        } catch (FFmpegFrameGrabber.Exception e) {
            log.info("\r\n{}\r\n启动拉流器失败，网络超时或视频源不可用", rtmpUrl);
            e.printStackTrace();
            AjaxResult.errorRun("启动拉流器失败，网络超时或视频源不可用："+e);
        }
        return true;
    }

    // 保存封面图的方法
    private void saveCoverImage(Frame frame) {
        try {
            String jpgPath=filePath+roomId+"_image.jpg";
            // 创建一个File对象
            File file = new File(jpgPath);
            // 获取文件的父目录
            File parentDir = file.getParentFile();
            // 如果父目录不存在，则创建它
            if (parentDir != null && !parentDir.exists()) {
                parentDir.mkdirs();
            }
            // 创建一个新的 FFmpegFrameRecorder 来保存图像为封面图
            FFmpegFrameRecorder coverRecorder = new FFmpegFrameRecorder(jpgPath, frame.imageWidth, frame.imageHeight);
            // 设置图像格式为 JPG (或者其他格式如 PNG)
            // 设置图像格式为 image2
            coverRecorder.setFormat("image2");  // 图像格式
            coverRecorder.setVideoCodec(avcodec.AV_CODEC_ID_MJPEG); // 使用 MJPEG 编码，生成 JPG 格式
            coverRecorder.setFrameRate(30);  // 设置一个常见帧率，虽然图像保存并不依赖帧率

            // 禁用音频流
            coverRecorder.setAudioChannels(0); // 禁用音频

            // 启动 recorder 来写图像
            coverRecorder.start();
            // 录制当前帧（保存图像）
            coverRecorder.record(frame);
            // 停止并释放 recorder
            coverRecorder.stop();
            coverRecorder.release();
            log.info("封面图已保存：cover_image.jpg");
        } catch (Exception e) {
            log.error("保存封面图失败：", e);
        }
    }

    public void setRunning(boolean running) {
        this.running = running;
    }
}
